package com.shu.rateLimiter;

import com.shu.timerTask.Base;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author ssm
 * @version V1.0
 * @description: 弊端：无法应对短时间的突发流量。
 * @date 2019/4/8 21:40
 */

public class SemaphoreRateLimter extends Base {
    public CountDownLatch downLatch2 = new CountDownLatch(1000);
    Semaphore semaphore = new Semaphore(2); // 同时能被2个线程访问
    AtomicInteger success = new AtomicInteger(0);
    AtomicInteger fail = new AtomicInteger(0);

    public void access(boolean abandon) {
        if (semaphore.getQueueLength() > 100) {
            System.out.println("当前有100个个人在排队访问!" + fail.incrementAndGet() + "访问失败!");

            if (abandon) {
                // 抛弃
                return;
            }

        }
        try {
            semaphore.acquire(); // 获取许可
            TimeUnit.MILLISECONDS.sleep(10);
            System.out.println(success.incrementAndGet() + "访问成功!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 释放该许可
            downLatch2.countDown();
        }
    }

    @Test
    @DisplayName("阻塞直到执行完毕")
    public void test2() throws InterruptedException, IOException {
        Runnable runnable = () -> {
            access(false);
        };

        // 模拟10000个线程同时访问
        for (int i = 0; i < 1000; i++) {
            cachedThreadPool.submit(runnable);
        }

        downLatch2.await();
        System.out.println("访问成功了: " + success.get());
        System.out.println("重试了: " + fail.get());
    }


    @Test
    @DisplayName("超过队列的丢弃")
    public void test3() throws InterruptedException, IOException {
        Runnable runnable = () -> {
            access(true);
        };

        // 模拟10000个线程同时访问
        for (int i = 0; i < 1000; i++) {
            cachedThreadPool.submit(runnable);
        }

        TimeUnit.SECONDS.sleep(5);
        System.out.println("访问成功了: " + success.get());
        System.out.println("访问失败了: " + fail.get());
    }
}
